package com.wish233.proxy;

import cn.hutool.core.util.IdUtil;
import com.wish233.application.RpcApplication;
import com.wish233.model.protocol.*;
import com.wish233.model.protocol.enums.ProtocolMessageSerializerEnum;
import com.wish233.model.protocol.enums.ProtocolMessageTypeEnum;
import com.wish233.model.register.ServiceMetaInfo;
import com.wish233.model.rpc.RpcRequest;
import com.wish233.model.rpc.RpcResponse;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.net.NetClient;
import io.vertx.core.net.NetSocket;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @author WHH
 */
@Slf4j
public class NetClientHandler {

    public static RpcResponse doRequest(RpcRequest rpcRequest, ServiceMetaInfo selectedService) throws ExecutionException, InterruptedException, TimeoutException {
        //发TPC请求
        Vertx vertx = Vertx.vertx();
        NetClient tcpClient = vertx.createNetClient();
        CompletableFuture<RpcResponse> responseFuture = new CompletableFuture<>();
        tcpClient.connect(selectedService.getServicePort(),
                selectedService.getServiceHost(),
                result -> {
                    if (!result.succeeded()) {
                        log.error("连接TCP失败！");
                        responseFuture.completeExceptionally(result.cause());
                        return;
                    }
                    NetSocket socket = result.result();
                    log.info("TCP服务器连接成功！");
                    //接收请求
                    socket.handler(new NetServerBufferHandlerWrapper(buffer -> {
                        try {
                            WishProtocol<RpcResponse> decode = (WishProtocol<RpcResponse>) ProtocolDecoder.decode(buffer);
                            log.info("解码成功！");
                            responseFuture.complete(decode.getBody());
                            log.info("成功");
                        } catch (IOException e) {
                            throw new RuntimeException("解码错误！", e);
                        }
                    }));
                    //构造消息体
                    WishProtocol.Header header = new WishProtocol.Header();
                    header.setMagicLow(ProtocolConstant.MAGIC_LOW);
                    header.setMagicHigh(ProtocolConstant.MAGIC_HIGH);
                    header.setVersion(ProtocolConstant.PROTOCOL_VERSION);
                    header.setSerializer((byte) ProtocolMessageSerializerEnum
                            .getEnumByValue(RpcApplication.getRpcConfig().getSerializer()).getKey());
                    header.setType((byte) ProtocolMessageTypeEnum.REQUEST.getKey());
                    header.setRequestId(IdUtil.getSnowflakeNextId());
                    WishProtocol<RpcRequest> tcpRequest = new WishProtocol<>();
                    tcpRequest.setHeader(header);
                    tcpRequest.setBody(rpcRequest);
                    try {
                        Buffer encode = ProtocolEncoder.encode(tcpRequest);
                        log.info("协议编码成功！");
                        socket.write(encode);
                        log.info("已经写入socket");
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }

                });
        //反序 列化返回响应
        // 响应回来再关闭连接
        RpcResponse response = responseFuture.get(32L, TimeUnit.SECONDS);
        tcpClient.close();
        return response;
    }

}
